#include "datacenter.h"

#include <QLabel>
#include <QImage>

namespace model {

DataCenter *DataCenter::getInstance()
{
    static DataCenter instance;
    return &instance;
}

DataCenter::~DataCenter()
{
    delete m_myself;
    delete m_friendList;
    delete m_chatSessionList;
    delete m_applyList;
    delete m_memberList;
    delete m_recentMessages;
    delete m_unreadMessageCount;
    delete m_searchUserResult;
    delete m_searchMessageResult;
}

void DataCenter::initWebsocket()
{
    m_netClient.initWebsocket();
}

void DataCenter::sendAuthentication()
{
    m_netClient.sendAuthentication();
}

void DataCenter::initDataFile()
{
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);  // 返回软件数据产生的临时文件路径
    QString filePath = basePath + "/WeChatSystem.json";

    // 不存在就创造一个文件
    QDir dir;
    if(!dir.exists(basePath)){
        dir.mkdir(basePath);
    }

    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
        LOG() << "打开文件失败";
        return ;
    }
    QString data = "{}";
    file.write(data.toUtf8());
    file.close();
}

void DataCenter::saveDataFile()
{
    QString base = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);  // 返回软件数据产生的临时文件路径
    QString filePath = base + "/WeChatSystem.json";

    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
        LOG() << "文件路径有误，找不到文件";
        return ;
    }
    LOG() << "缓存路径：" << filePath;

    // 保存必要的缓存信息内容，如：登入会话ID loginSessionId， 未读消息unreadMessageCount
    QJsonObject jsonObj;
    // 1.登录会话ID
    jsonObj["loginSessionId"] = m_loginSessionId;
    // 2.未读消息
    QJsonObject jsonUnread;
    for (auto iter = m_unreadMessageCount->begin(); iter != m_unreadMessageCount->end(); ++iter) {
        jsonUnread[iter.key()] = iter.value();
    }
    jsonObj["unread"] = jsonUnread;

    // 转换成Json格式的字符串，写入文件
    QJsonDocument jsonDoc(jsonObj);
    file.write(jsonDoc.toJson());

    file.close();
}

void DataCenter::loadDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/WeChatSystem.json";

    // 文件不存在就初始化一下
    QFileInfo fileInfo(filePath);
    if(!fileInfo.exists()){
        initDataFile();
    }

    QFile file(filePath);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        LOG() << "打开文件失败";
        return;
    }
    QString data = file.readAll();

    QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8());  // 直接解析字符串
    if (jsonDoc.isNull()) {
        LOG() << "解析Json文件失败！文件格式有误";
        return;
    }
    QJsonObject jsonObj(jsonDoc.object());

    // 加载缓存文件内容
    m_loginSessionId = jsonObj["m_loginSessionId"].toString();

    QJsonObject jsonUnread(jsonObj["unread"].toObject());
    m_unreadMessageCount->clear();
    for(auto iter = jsonUnread.begin(); iter != jsonUnread.end(); ++iter){
        m_unreadMessageCount->insert(iter.key(), iter.value().toInt());
    }

    file.close();
}

void DataCenter::addUnreadMsg(const QString& chatSessionId)
{
    ++(*m_unreadMessageCount)[chatSessionId];
    // 手动保存一下未读消息个数，以保证客户端重新连接后还有准确的未读消息个数
    saveDataFile();
}

void DataCenter::clearUnreadMsg(const QString &chatSessionId)
{
    (*m_unreadMessageCount)[chatSessionId] = 0;
    saveDataFile();
}

void DataCenter::getMyselfAsync()
{
    m_netClient.getMyself(m_loginSessionId);
}

void DataCenter::resetMyself(const im::GetUserInfoRsp &resp)
{
    if(m_myself == nullptr){
        m_myself = new UserInfo();
    }
    m_myself->load(resp.userInfo());
}

void DataCenter::getFriendListAsync()
{
    m_netClient.getFriendList(m_loginSessionId);
}

void DataCenter::resetFriendList(const im::GetFriendListRsp &resp)
{
    if(m_friendList == nullptr){
        m_friendList = new QList<UserInfo>();
    }else{
        m_friendList->clear();
    }

    QList<im::UserInfo> friendList = resp.friendList();
    for (auto& f : friendList) {
        UserInfo userInfo;
        userInfo.load(f);
        m_friendList->push_back(userInfo);
    }
}

void DataCenter::getChatSessionListAsync()
{
    m_netClient.getChatSessionList(m_loginSessionId);
}

void DataCenter::resetChatSessionList(const im::GetChatSessionListRsp &resp)
{
    if(m_chatSessionList == nullptr){
        m_chatSessionList = new QList<chatSessionInfo>();
    }else{
        m_chatSessionList->clear();
    }

    QList<im::ChatSessionInfo> chatSessionList = resp.chatSessionInfoList();
    for (const auto& f : chatSessionList) {
        chatSessionInfo chatSessionInfo;
        chatSessionInfo.load(f);
        m_chatSessionList->push_back(chatSessionInfo);
    }
}

void DataCenter::getApplyListAsync()
{
    m_netClient.getApplyList(m_loginSessionId);
}

void DataCenter::resetApplyList(const im::GetPendingFriendEventListRsp &resp)
{
    if(m_applyList == nullptr){
        m_applyList = new QList<UserInfo>();
    }else{
        m_applyList->clear();
    }

    QList<im::FriendEvent> applyList = resp.event().toList();
    for(const auto a : applyList){
        UserInfo userInfo;
        userInfo.load(a.sender());
        m_applyList->push_back(userInfo);
    }
}

void DataCenter::getRecentMsgListAsync(const QString &chatSessionId, bool isUI)
{
    m_netClient.getRecentMsgList(m_loginSessionId, chatSessionId, isUI);
}

void DataCenter::resetRecentMsgList(const QString& chatSessionId, const im::GetRecentMsgRsp &resp)
{
    QList<Message>& messageList = (*m_recentMessages)[chatSessionId];
    messageList.clear();

    for(const auto& msgInfo : resp.msgList()){
        Message msg;
        msg.load(msgInfo);
        messageList.push_back(msg);
    }
}

chatSessionInfo* DataCenter::findChatSessionBySessionId(const QString &chatSessionId)
{
    if(m_chatSessionList == nullptr)
        return nullptr;

    for (auto& c : *m_chatSessionList) {
        if(c.m_chatSessionId == chatSessionId)
            return &c;
    }
    return nullptr;
}

chatSessionInfo *DataCenter::findChatSessionByUserId(const QString &userId)
{
    if(m_chatSessionList == nullptr)
        return nullptr;

    for (auto& c : *m_chatSessionList) {
        if(c.m_userId == userId)
            return &c;
    }
    return nullptr;
}

void DataCenter::topChatSessionInfo(const chatSessionInfo &chat)
{
    auto iter = m_chatSessionList->begin();
    for (; iter != m_chatSessionList->end(); ++iter) {
        if(iter->m_chatSessionId == chat.m_chatSessionId)
            break;
    }

    if(iter == m_chatSessionList->end()){
        return;
    }
    // 先备份
    chatSessionInfo backup = chat;
    // 删除这个原有的成员
    m_chatSessionList->erase(iter);
    // 重新头插
    m_chatSessionList->push_front(backup);
}

void DataCenter::sendMessageAsync(const QString &chatSessionId,const QString& content)
{
    m_netClient.sendMessage(m_loginSessionId, chatSessionId, model::MessageType::TEXT_TYPE, content.toUtf8(), "");
}

void DataCenter::sendImageMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    m_netClient.sendMessage(m_loginSessionId, chatSessionId, model::MessageType::IMAGE_TYPE, content, "");
}

void DataCenter::sendFileMessageAsync(const QString &chatSessionId, const QString &fileName, const QByteArray &content)
{
    m_netClient.sendMessage(m_loginSessionId, chatSessionId, model::MessageType::FILE_TYPE, content, fileName);
}

void DataCenter::sendSpeechMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    m_netClient.sendMessage(m_loginSessionId, chatSessionId, model::MessageType::SPEECH_TYPE, content, "");
}

void DataCenter::addMessage(const Message &msg)
{
    QList<Message>& msgList = (*m_recentMessages)[msg.m_chatSessionId];
    msgList.push_back(msg);
}

void DataCenter::receiveMessage(const QString &chatSessionId)
{
    // 判断是否选中会话，选中就展示
    if(getCurrentChatSessionId() == chatSessionId){
        Message msg = (*m_recentMessages)[chatSessionId].back();
        emit receiveMessageDone(msg);
    }else{
    // 没选中，显示未读消息
    // 然后通知给界⾯, 让界⾯更新未读消息数字.
    // 当对应的会话被点击, 则对应的未读消息的数字
    // 未读消息数⽬需要在硬盘保存, 以备在重启后重新获得
    // 对于当前会话的窗⼝, 不需要保存这个数据
        addUnreadMsg(chatSessionId);
    }

    // 2.更新UI
    emit updateLastMessage(chatSessionId);
}

void DataCenter::changeNickNameAsync(const QString &newNick)
{
    m_netClient.changeNickName(m_loginSessionId, newNick);
}

void DataCenter::resetNickName(const QString &newNick)
{
    m_myself->m_nickName = newNick;
}

void DataCenter::changeDescriptionAsync(const QString& descption)
{
    m_netClient.changeDescription(m_loginSessionId, descption);
}

void DataCenter::resetDescption(const QString& description)
{
    m_myself->m_description = description;
}

void DataCenter::changeAvatarAsync(const QByteArray &imageByte)
{
    m_netClient.changeAvatar(m_loginSessionId, imageByte);
}

void DataCenter::resetAvatar(const QByteArray &avatar)
{
    m_myself->m_avatar = makeIcon(avatar);
}

void DataCenter::getVerifyCodeAsync(const QString &phone)
{
    m_netClient.getVerifyCode(phone);
}

void DataCenter::resetVerifyCode(const QString &verifyCode)
{
    m_currentVerifyCodeId = verifyCode;
}

void DataCenter::changePhoneAsync(const QString &phoneTochange, const QString &codeId, const QString& code)
{
    m_netClient.changePhone(m_loginSessionId, phoneTochange, codeId, code);
}

void DataCenter::resetPhone(const QString &phone)
{
    m_myself->m_phone = phone;
}

void DataCenter::deleteFriendAsync(const QString &userId)
{
    m_netClient.deleteFriend(m_loginSessionId, userId);
}

void DataCenter::removeFriend(const QString &userId)
{
    if(!m_friendList){
        return ;
    }

    // 删除好友
    m_friendList->removeIf([=](const UserInfo &friendObj) {
        return friendObj.m_userId == userId;
    });
    // 删除会话
    m_chatSessionList->removeIf([=](const chatSessionInfo& chatList){
        // 群聊不删
        if(chatList.m_userId == ""){
            return false;
        }
        // 自己不删
        else if(chatList.m_userId != userId){
            return false;
        }
        // 如果是当前选中会话，则清空聊天内容
        else if(chatList.m_userId == getCurrentChatSessionId()){
            emit clearCurrentSession();
        }
        return true;
    });
}

void DataCenter::addFriendApplyAsync(const QString &userId)
{
    m_netClient.addFriendApply(m_loginSessionId, userId);
}

void DataCenter::acceptFriendApplyAsync(const QString &userId)
{
    m_netClient.acceptFriendApply(m_loginSessionId, userId);
}

UserInfo DataCenter::removeFromApplyList(const QString &userId)
{
    UserInfo userInfo;
    if(m_applyList == nullptr){
        LOG() << "applyList 为空";
        return userInfo;
    }
    // 删除好友申请
    for(auto iter = m_applyList->begin(); iter != m_applyList->end(); ++iter){
        if(iter->m_userId == userId){
            userInfo = *iter;
            m_applyList->erase(iter);
            break;
        }
    }
    return userInfo;
}

void DataCenter::createGroupChatSessionAsync(const QList<QString> &member)
{
    m_netClient.createGroupChatSession(m_loginSessionId, member);
}

void DataCenter::getMemberListAsync(const QString& chatSessionId)
{
    m_netClient.getMemberList(m_loginSessionId, chatSessionId);
}

void DataCenter::resetMemberList(const QString &chatSessionId, const QList<im::UserInfo> &memberList)
{
    QList<UserInfo>& list = (*m_memberList)[chatSessionId];
    list.clear();

    for(auto m : memberList){
        UserInfo member;
        member.load(m);
        list.append(member);
    }
}

void DataCenter::searchUserAsync(const QString& searchKey)
{
    m_netClient.searchUser(m_loginSessionId, searchKey);
}

void DataCenter::resetSearchUserResult(const QList<im::UserInfo> &userList)
{
    if(m_searchUserResult == nullptr){
        m_searchUserResult = new QList<UserInfo>();
    }else{
        // 清空上次搜索的结果
        m_searchUserResult->clear();
    }
    for(const auto& user : userList){
        model::UserInfo userInfo;
        userInfo.load(user);
        m_searchUserResult->append(userInfo);
    }
}

void DataCenter::searchMessageAsync(const QString& searchKey)
{
    m_netClient.searchMessage(m_loginSessionId, getCurrentChatSessionId(), searchKey);
}

void DataCenter::searchMessageByTimeAsync(const QDateTime &begTime, const QDateTime &endTime)
{
    m_netClient.searchMessageByTime(m_loginSessionId, getCurrentChatSessionId(), begTime, endTime);
}

void DataCenter::resetSearchMessageResult(const QList<im::MessageInfo> &messageResult)
{
    if(m_searchMessageResult == nullptr){
        m_searchMessageResult = new QList<Message>();
    }
    m_searchMessageResult->clear();

    for(const auto& m : messageResult){
        Message msg;
        msg.load(m);
        m_searchMessageResult->append(msg);
    }
}

void DataCenter::userLoginAsync(const QString& user, const QString& password)
{
    // 服务器返回loginSessionId
    m_netClient.userLogin(user, password);
}

void DataCenter::resetLoginSessionId(const QString& loginSessionID)
{
    m_loginSessionId = loginSessionID;
    saveDataFile();
}

void DataCenter::userRegisterAsync(const QString& user, const QString& password)
{
    // 服务器返回loginSessionId
    m_netClient.userRegister(user, password);
}

void DataCenter::phoneLoginAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    m_netClient.phoneLogin(phone, verifyCodeId, verifyCode);
}

void DataCenter::phoneRegisterAsync(const QString &phone, const QString &verifyCode)
{
    // 服务器返回loginSessionId
    m_netClient.phoneRegister(phone, m_currentVerifyCodeId, verifyCode);
}

void DataCenter::getSingleFileAsync(const QString &fileId)
{
    m_netClient.getSingleFile(m_loginSessionId, fileId);
}

void DataCenter::speechConvertTextAsync(const QString& fileId, const QByteArray& content)
{
    m_netClient.speechConvertText(m_loginSessionId, fileId, content);
}

QList<UserInfo>* DataCenter::getMemberList(const QString &chatSessionId)
{
    if(!m_memberList->contains(chatSessionId)){
        return nullptr;
    }
    return &(*m_memberList)[chatSessionId];
}

const QList<Message> *DataCenter::getRecentMsgList(const QString &chatSessionId)
{
    if(!m_recentMessages->contains(chatSessionId))
        return nullptr;

    QList<Message>& recentMsgList = (*m_recentMessages)[chatSessionId];
    return &recentMsgList;
}

UserInfo* DataCenter::getFriendById(const QString &userID)
{
    if (this->m_friendList == nullptr) {
        return nullptr;
    }
    for (auto& f : *m_friendList) {
        if (f.m_userId == userID) {
            return &f;
        }
    }
    return nullptr;
}

void DataCenter::setCurrentChatSessionId(const QString &chatSessionId)
{
    m_currentChaSessionId = chatSessionId;
}

DataCenter::DataCenter(QObject *parent)
    : QObject{parent}, m_netClient(this)
{
    m_memberList = new QHash<QString, QList<UserInfo>>();
    m_recentMessages = new QHash<QString,QList<Message>>();
    m_unreadMessageCount = new QHash<QString, int>();

    loadDataFile();  // 加载一下缓存文件数据
}

} // end namespace
